﻿#include "stdafx.h"
#include "Animate.h"
#include "Shader.h"

Animate::Animate()
{
	m_animData = 0;
	m_matrixs = 0;
	m_disabledLastFrame = false;
	m_currAnimation = 0;
	m_currAnimationIndex = 0;
	m_frameRate = 8;
	m_deltaTimeCount = 0;
	m_interpolation = true;
}

Animate::Animate(AnimationData *animData) : Animate()
{
	SetAnimData(animData);
}

Animate::~Animate()
{
	if (m_matrixs) delete[] m_matrixs;
}

void Animate::SetAnimData(AnimationData *animData)
{
	m_animData = animData;
	m_matrixs = new glm::mat4[animData->nodes.size()];
	SetAnimation(0, 0);
}

void Animate::SetParentMatrix(glm::mat4 *mat)
{
	//m_parentMat = mat;
}

void Animate::SetAnimation(int animIndex, int frameIndex, PlayState playState)
{
	m_currAnimationIndex = animIndex;
	m_currAnimation = &m_animData->animations[animIndex];
	Play(frameIndex, playState);

	UpdateMatrix();
	if (m_cb_enterFrame) m_cb_enterFrame(frameIndex);
}

int Animate::GetCurrAnimIndex()
{
	return m_currAnimationIndex;
}

void Animate::Update()
{
	Update(FrameTime::GetInstance()->GetDeltaTime());
}

bool Animate::Update(float deltaTime)
{
	if (m_frameCount == 1 || m_animPlayState_curr == PlayState::Stop || m_currAnimation == NULL)
		return false;

	unsigned int nextFrame = m_currFrame + 1;
	if (nextFrame >= m_frameCount)
	{
		if (m_disabledLastFrame)
		{
			if (m_animPlayState == PlayState::Once)
			{
				m_animPlayState_curr = m_animPlayState = PlayState::Stop;
				if (m_cb_animEnd) m_cb_animEnd();
				return false;
			}
			else
			{
				m_currFrame = 0;
				nextFrame = 1;
				if (m_cb_enterFrame) m_cb_enterFrame(m_currFrame);
			}
		}
		else nextFrame = 0;
	}

	m_deltaTimeCount += deltaTime * m_frameRate;
	if (m_deltaTimeCount >= 1.0f)
	{
		if (m_currFrame >= m_frameCount - 1)
		{
			if (m_animPlayState == PlayState::Once)
			{
				m_animPlayState_curr = m_animPlayState = PlayState::Stop;
				if (m_cb_animEnd) m_cb_animEnd();
				return false;
			}
		}
		m_deltaTimeCount -= 1.0f;
		if (m_deltaTimeCount > 1.0f) m_deltaTimeCount = 0.0f;
		m_currFrame = nextFrame;
		UpdateMatrix();
		if (m_cb_enterFrame) m_cb_enterFrame(m_currFrame);
		return true;
	}
	else if (m_interpolation)
	{
		//在两帧间进行插值
		auto curr = &m_currAnimation->frames[m_currFrame].nodeOffsets[0];
		//骨骼插值
		auto count = m_animData->nodes.size();
		auto joints = new AnimationData::NodeOffset[count];
		int i = 0;
		for (auto &next : m_currAnimation->frames[nextFrame].nodeOffsets)
		{
            if (i >= count)
                break;
			joints[i].position = glm::mix(curr[i].position, next.position, m_deltaTimeCount);
			joints[i].rotation = glm::slerp<float>(curr[i].rotation, next.rotation, m_deltaTimeCount);
			i++;
		}

		//碰撞盒插值
		//min = Lerp(curr.min, next.min, interpTime);
		//max = Lerp(curr.max, next.max, interpTime);

		//帧偏移插值
		auto frameOffSize = m_currAnimation->frameOffsets.size();
		glm::vec3 *frameOffs = 0;
		if (frameOffSize)
		{
			frameOffs = new glm::vec3[frameOffSize];
			auto curr = &m_currAnimation->frameOffsets[m_currFrame];
			auto next = &m_currAnimation->frameOffsets[nextFrame];
			for (int i = 0; i < frameOffSize; i++) frameOffs[i] = glm::mix(curr[i], next[i], m_deltaTimeCount);
		}
		UpdateMatrix(joints, frameOffs);
		delete[] joints;
		if (frameOffs) delete[] frameOffs;
		return true;
	}
	else return false; //未更新矩阵
}

void Animate::UpdateMatrix()
{
	auto *frameOffset = m_currAnimation->frameOffsets.size() ? &m_currAnimation->frameOffsets[m_currFrame] : nullptr;
	UpdateMatrix(&m_currAnimation->frames[m_currFrame].nodeOffsets[0], frameOffset);
}

void Animate::UpdateMatrix(AnimationData::NodeOffset *nodeOffsets, glm::vec3 *frameOffset)
{
	auto &nodes = m_animData->nodes;
	for (int i = 0; i < nodes.size(); i++)
	{
		auto &node = nodes[i];
		if (node.name.empty()) continue;
        m_matrixs[i] = glm::mat4_cast(nodeOffsets[i].rotation);
		//m_matrixs[i] = glm::toMat4(nodeOffsets[i].rotation);
		//m_matrixs[i][3].x = nodeOffsets[i].position.x;
		//m_matrixs[i][3].y = nodeOffsets[i].position.y;
		//m_matrixs[i][3].z = nodeOffsets[i].position.z;
		VectorCopy(&m_matrixs[i][3].x, &nodeOffsets[i].position.x, 3);
		if (node.parentID == -1)
		{
			//if (m_parentMat) m_matrixs[i] = (*m_parentMat)*m_matrixs[i];
			if (frameOffset)
			{
				//m_matrixs[i][3].z += frameOffset->z;
				//VectorAdd(&m_matrixs[i][3].x, &frameOffset->x, 3);
			}
			//m_min[0] = m_max[0] = m_matrix[i].mat34[0][3];
			//m_min[1] = m_max[1] = m_matrix[i].mat34[1][3];
			//m_min[2] = m_max[2] = m_matrix[i].mat34[2][3];
		}
		else
		{
			m_matrixs[i] = m_matrixs[node.parentID] * m_matrixs[i];
			//获取骨骼坐标的极致作为Bounding Box坐标
			//float f1;
			//for (int j=0;j<3;j++)
			//{
			//	f1=m_matrixs[i].mat34[j][3];
			//	if (m_min[j]>f1) m_min[j]=f1;
			//	if (m_max[j]<f1) m_max[j]=f1;
			//}
		}
	}
}

void Animate::SetFrameRate(float fr)
{
	m_frameRate = fr;
}

glm::vec3 &Animate::GetFirstFrameRootNodePosition()
{
	int i = 0;
	for (auto &node : m_animData->nodes)
	{
		if (node.parentID == -1) break;
		i++;
	}
	return m_currAnimation->frames[0].nodeOffsets[i].position;
}

int Animate::GetBoneTransformMatrixs(glm::mat4 **mats)
{
	*mats = m_matrixs;
	return m_animData->nodes.size();
}

int Animate::GetNodeIndex(char *nodeName)
{
	int i = 0;
	bool fok = false;
	for (auto &node : m_animData->nodes)
	{
		if (node.name.compare(nodeName) == 0)
		{
			fok = true;
			break;
		}
		i++;
	}
	return fok ? i : -1;
}

glm::mat4 *Animate::GetBoneTransformMatrix(int nodeIndex)
{
	return m_matrixs + nodeIndex;
}

glm::mat4 *Animate::GetBoneTransformMatrix(char *nodeName)
{
	int i = GetNodeIndex(nodeName);
	return i < 0 ? nullptr : m_matrixs + i;
}

void Animate::DisabledLastFrame(bool f)
{
	m_disabledLastFrame = f;
}

void Animate::SetInterpolation(bool f)
{
	m_interpolation = f;
}

void Animate::Play(int frameIndex, PlayState playState)
{
	m_frameCount = m_currAnimation->frames.size();
	m_currFrame = frameIndex >= m_frameCount ? 0 : frameIndex;
	m_deltaTimeCount = 0.f;
	m_animPlayState_curr = m_animPlayState = playState;
}

void Animate::Pause()
{
	m_animPlayState_curr = PlayState::Stop;
}

void Animate::Continue()
{
	m_animPlayState_curr = m_animPlayState;
}

Animate::PlayState Animate::GetCurrPlayState()
{
	return m_animPlayState_curr;
}

int Animate::GetCurrFrameIndex()
{
	return m_currFrame;
}
